#ifndef POKUS_H_JM_20120918
#define POKUS_H_JM_20120918

#include "RootBox.h"

#include <bobox_box.hpp>
#include <bobox_types.hpp>

#include <iostream>
#include <sstream>

namespace jm4bbx {
	
	struct InBoxDescriptor {
		//static const char* BOX_ID;
		static const  groupType INPUT_GROUP;
		static const  groupType OUTPUT_GROUP_1;	
		static const  groupType OUTPUT_GROUP_2;	
		static const  columnType INPUT_COLUMN;
		static const  columnType OUTPUT_COLUMN_1;
		static const  columnType OUTPUT_COLUMN_2;
		static const  inType IN_ARC;
		static const  bobox::outarc_index_type OUT_ARC_1;
		static const  bobox::outarc_index_type OUT_ARC_2;


	};

	class InBox : public Box/*<InBoxDescriptor>*/ {
	public:

		typedef InBoxDescriptor BoxIO;

		InBox(bobox::box_id_type id, bobox::box_tid_type tid, bobox::request *req, 
			const bobox::parameters &params) 
			: Box(id, tid, req, params), typeNum_(0) {

				
				if (params.has_parameter("type")) {
					params.get_parameter("type", typeNum_);
				}
		}

		virtual void initImpl() {

			add_group(BoxIO::INPUT_GROUP, 
				BoxIO::INPUT_COLUMN, 
				get_input_descriptors(BoxIO::IN_ARC));

			add_group(BoxIO::OUTPUT_GROUP_1, 
				BoxIO::OUTPUT_COLUMN_1, 
				get_output_descriptors(BoxIO::OUT_ARC_1));


			add_group(BoxIO::OUTPUT_GROUP_2, 
				BoxIO::OUTPUT_COLUMN_2, 
				get_output_descriptors(BoxIO::OUT_ARC_2));

			wait4Receive();
		}

		virtual void sync_mach_etwas() {

			//const group& ig = get_group(BoxIO::INPUT_GROUP);
			//if (ig.poisoned_) {
			//	send_poisoned(BoxIO::OUT_ARC_1);
			//	send_poisoned(BoxIO::OUT_ARC_2);
			//	return;
			//}

			const size_t size = 10;
			allocate(BoxIO::OUTPUT_GROUP_1, size);
			get_group(BoxIO::OUTPUT_GROUP_1).setWritePosition(size);//wrpos_ = size;

			allocate(BoxIO::OUTPUT_GROUP_2, size);
			get_group(BoxIO::OUTPUT_GROUP_2).setWritePosition(size);//wrpos_ = size;


			for (size_t i = 0; i < size; ++i) {

				get_data<bobox::int_policy>(BoxIO::OUTPUT_COLUMN_1)[i] = typeNum_;
				get_data<bobox::int_policy>(BoxIO::OUTPUT_COLUMN_2)[i] = typeNum_*2;
			}

			Group og1 = get_group(BoxIO::OUTPUT_GROUP_1);

			og1.setWriteBegin(0);//wrbegin_ = 0;
			og1.setWritePosition(size);//wrpos_ = size;
			og1.setWriteEnd(size);//wrend_ = size;

			Group og2 = get_group(BoxIO::OUTPUT_GROUP_2);

			og2.setWriteBegin(0);//wrbegin_ = 0;
			og2.setWritePosition(size);//wrpos_ = size;
			og2.setWriteEnd(size);//wrend_ = size;

			if (typeNum_ < 5) {
				send(BoxIO::OUT_ARC_1, BoxIO::OUTPUT_GROUP_1); 
				send(BoxIO::OUT_ARC_2, BoxIO::OUTPUT_GROUP_2);
			}

			wait4Receive();

		}
	private:
		int typeNum_;

		void wait4Receive() {
			receive(BoxIO::IN_ARC, BoxIO::INPUT_GROUP);
		}

	};


	struct OutBoxDescriptor {
		//static const char* BOX_ID;
		static const  groupType INPUT_GROUP_1;
		static const  groupType INPUT_GROUP_2;
		static const  groupType OUTPUT_GROUP;	
		static const  columnType INPUT_COLUMN_1;
		static const  columnType INPUT_COLUMN_2;
		static const  columnType OUTPUT_COLUMN;
		static const  inType IN_ARC_1;
		static const  inType IN_ARC_2;
		static const  bobox::outarc_index_type OUT_ARC;

	};

	class OutBox : public Box/*<OutBoxDescriptor>*/ {
	public:
		typedef OutBoxDescriptor BoxIO;

		OutBox(bobox::box_id_type id, bobox::box_tid_type tid, bobox::request *req, 
			const bobox::parameters &params) 
			: Box(id, tid, req, params) {


		}

		virtual void initImpl() {

			add_group(BoxIO::INPUT_GROUP_1, 
				BoxIO::INPUT_COLUMN_1, 
				get_input_descriptors(BoxIO::IN_ARC_1));

			add_group(BoxIO::INPUT_GROUP_2, 
				BoxIO::INPUT_COLUMN_2, 
				get_input_descriptors(BoxIO::IN_ARC_2));


			add_group(BoxIO::OUTPUT_GROUP, 
				BoxIO::OUTPUT_COLUMN, 
				get_output_descriptors(BoxIO::OUT_ARC));

			wait4Receive();
		}

		virtual void sync_mach_etwas() {

			Group ig = get_group(BoxIO::INPUT_GROUP_1);
			if (ig.isPoisoned()/*poisoned_*/) {
				send_poisoned(BoxIO::OUT_ARC);
				return;
			}

			const size_t size = 10;

			for (size_t i = 0; i < size; ++i) {
				std::stringstream stream;
				stream << getBoxInstanceId() << " data " << 
				get_data<bobox::int_policy>(BoxIO::INPUT_COLUMN_1)[i] <<  " & " <<
				get_data<bobox::int_policy>(BoxIO::INPUT_COLUMN_2)[i] << std::endl;

				std::cout << stream.str() ;

			}

			send(BoxIO::OUT_ARC, BoxIO::OUTPUT_GROUP);

			wait4Receive();

		}
	private:
		void wait4Receive() {
			receive(BoxIO::IN_ARC_1, BoxIO::INPUT_GROUP_1);
			receive(BoxIO::IN_ARC_2, BoxIO::INPUT_GROUP_2);
		}

	};


} // namespace jm4bbx

#endif
